<?php
/**
 * Gère des dates
 *
 * @category librairies
 * @package planning
 *
 * @author Mickaël CASTANHEIRO
 * @version 1.0
 */
class Date extends DateTime {

    /**
     * Constructeur de la classe     *
     * @return Date Instance crée
     */
    public function __construct($_date=null) {
	try {
	    if ( preg_match('!^(0[1-9]|[12][0-9]|3[01])[/-](0[1-9]|1[012])[/-](19|20)[0-9]{2}$!', $_date) ) {
		$_date = str_replace('/', '-', $_date);
	    }

	    parent::__construct($_date);
	}
	catch(Exception $error) {
	    echo $error->getMessage();
	    exit(1);
	}
    }


    /**
     * Crée une date depuis un champ DATE de la base de données
     * @param <string> Date issue de la bdd format yyyy-mm-dd
     * @return <Date> Date créee
     */
    public static function fromSGBD($_date) {
	return new Date(Date::createFromFormat('Y-m-d', $_date)->format('d/m/Y'));
    }

    /**
     * Crée une date depuis un champ DATE de l'a base de données'url
     * @param <string> Date issue d'une url au format d-m-Y
     * @return <Date> Date créee
     */
    public static function fromURL($_date) {
	return new Date(Date::createFromFormat('d-m-Y', $_date)->format('d/m/Y'));
    }

    /**
     * Crée une date depuis un champ DATE de formulaire
     * @param <string> Date issue d'un formulaire format d/m/Y
     * @return <Date> Date créee
     */
    public static function fromFormulaire($_date) {
	return new Date(Date::createFromFormat('d/m/Y', $_date)->format('d/m/Y'));
    }

    /**
     * Crée une date sgbd sans passer pa la création d'un objet Date
     * @param <string> Date au format habituel
     * @return <string> Date au format bdd
     */
    public function toSGBD() {
	return $this->format('Y-m-d');
    }

    /**
     * Crée un format de date qu'on puisse parser dans l'url
     * @return <string> Date format url
     */
    public function toURL() {
	return $this->format('d-m-Y');
    }

    /**
     * Crée un format de date qu'on puisse afficher dans un formulaire
     * @return <string> Date format url
     */
    public function toFormulaire() {
	return $this->format('d/m/Y');
    }


    /**
     * Retourne la date d'aujourd'hui
     * @return (Date) Date d'aujourd'hui
     */
    public static function today() {
	return new Date();
    }

    /**
     * Retourne la différence entre deux dates
     * @param <string> Première heure
     * @param <string> Seconde heure
     * @return <string> Différence entre les deux heures (en heures)
     */
    public static function timeDifference($_h1, $_h2) {
	$_h1_heures = substr($_h1,0,2);
	$_h1_minutes = substr($_h1, 3,2);
	$_h2_heures = substr($_h2,0,2);
	$_h2_minutes = substr($_h2, 3,2);

	// h1 supérieur à h2
	if (($_h1_heures > $_h2_heures) OR
		(($_h1_heures == $_h2_heures) AND ($_h1_minutes > $_h2_minutes)) ) {
	    // Minutes
	    if ( $_h1_minutes < $_h2_minutes ) {
		$_h1_heures--;
		$_h1_minutes += 60;
	    }
	    $_h_minutes = $_h1_minutes-$_h2_minutes;
	    while ( strlen($_h_minutes) < 2 ) $_h_minutes = '0'.$_h_minutes;

	    // Heures
	    $_h_heures = $_h1_heures - $_h2_heures;
	    while ( strlen($_h_heures) < 2 ) $_h_heures= '0'.$_h_heures;

	    return $_h_heures . 'h' . $_h_minutes;
	}
	elseif (($_h1_heures < $_h2_heures) OR
		(($_h1_heures == $_h2_heures) AND ($_h1_minutes < $_h2_minutes)) ) {
	    // Minutes
	    if ( $_h2_minutes < $_h1_minutes ) {
		$_h2_heures--;
		$_h2_minutes += 60;
	    }
	    $_h_minutes = $_h2_minutes-$_h1_minutes;
	    while ( strlen($_h_minutes) < 2 ) $_h_minutes = '0'.$_h_minutes;

	    // Heures
	    $_h_heures = $_h2_heures - $_h1_heures;
	    while ( strlen($_h_heures) < 2 ) $_h_heures= '0'.$_h_heures;

	    return $_h_heures . ':' . $_h_minutes;
	}
	else return '00:00';
    }

    /**
     * Indique si deux créneaux horaires se chevauchent (ou l'un est inclus dans l'autre)
     * @param <string> Heure de début du premier créneau au format hh:mm(:ss)
     * @param <string> Heure de fin du premier créneau au format hh:mm(:ss)
     * @param <string> Heure de début du second créneau au format hh:mm(:ss)
     * @param <string> Heure de fin du second créneau au format hh:mm(:ss)
     * @return <boolean> Les créneaux se chevauchent
     */
    public static function timeOver($_heureDebut1, $_heureFin1, $_heureDebut2, $_heureFin2) {
	// Ajoute les secondes si nécessaire
	if ( strlen($_heureDebut1) <= 5 ) $_heureDebut1 .= ':00';
	if ( strlen($_heureFin1) <= 5 ) $_heureFin1 .= ':00';
	if ( strlen($_heureDebut2) <= 5 ) $_heureDebut2 .= ':00';
	if ( strlen($_heureFin2) <= 5 ) $_heureFin2 .= ':00';

	// Crée des datetime pour la comparaison
	$heureDebut1 = DateTime::createFromFormat('H:i:s', $_heureDebut1);
	$heureFin1 = DateTime::createFromFormat('H:i:s', $_heureFin1);
	$heureDebut2 = DateTime::createFromFormat('H:i:s', $_heureDebut2);
	$heureFin2 = DateTime::createFromFormat('H:i:s', $_heureFin2);

	return ( ($heureFin1 > $heureDebut2) AND ($heureFin2 > $heureDebut1) );
    }

    /**
     * Transforme une heure en float
     * @param <strong> heure au format hh:mm(:ss)
     * @return <float> heure en format float
     */
    public static function timeToFloat($_heure) {
	$heure = explode(':', $_heure);

	$result = floatval($heure[0]);
	$result += floatval($heure[1]) / 60;
	if ( !empty($result[2]) )
	    $result += floatval($heure[2]) / 3600;

	return $result;
    }

    /**
     * Formate une date au format texte
     * Surcharge de la méthode format
     * @param <string> Format de la date à afficher
     * @return <string> Date formattée
     */
    public function format($_format) {
	$anglais  = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday',
		'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
	$francais = array('Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche',
		'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre');

	if ( ($pos=strpos('j', $_format)) !== false ) {
	    // Découpe le j pour insérer un 'er'
	    $jour = parent::format('j');
	    if ( $jour=='1' ) $jour = '\1\e\r';
	    return parent::format(str_replace('j', $jour, $_format));
	}
	else {
	    return str_replace($anglais, $francais, parent::format($_format));
	}
    }


    /**
     * @function jourDeLaSemaine
     * @param <integer> Numéro du jour demandé (0 (lundi) à 6 (dimanche))
     * @param <boolean> Numéro du jour passé au format anglais ( 0 (dimanche) à 6 (samedi) ); default false
     * @return <Date> Date d'un jour de la semaine du jour en cours
     */
    public function jourDeLaSemaine($_jour = 0, $_englishWeek = false) {
	//
	if($_englishWeek) {
	    $_jour -= 1; // Retire un (dimanche passe à -1, lundi passe 1 à zéro... etc)
	    if ( $_jour == -1 ) $_jour = 6; // Dimanche anglais = 0 (ici -1); Dimanche Francais = 6
	}

	// Position du jour dans la semaine en cours
	$position = $this->format('w') - 1; // Retire un (dimanche passe à -1, lundi passe 1 à zéro... etc)
	if ( $position == -1 ) $position = 6; // Dimanche anglais = 0 (ici -1); Dimanche Francais = 6

	$date = new Date($this->format('Y/m/d'));
	$date->modify('-'.$position.' day'); // Retire le nombre de jours qui nous sépare de lundi
	$date->modify('+'.$_jour.' day'); // Ajoute le nombre de jours voulus
	return $date; // Retourne la nouvelle date
    }

    /**
     * Retourne un jour du mois du jour en cours
     * @param <integer> Numéro du jour demandé
     * @return <Date> Date d'un jour du mois du jour en cours
     */
    public function jourDuMois($_jour = 0) {
	// 31e jour... peut être pas
	$mois = $this->format('m');
	if ( $_jour == 31 ) {
	    $_jour = $this->format('t');
	}

	$date = new Date($this->format('Y').'/'.$mois.'/'.$_jour);
	return $date; // Retourne la nouvelle date
    }

    /**
     *@function demain
     * @param <string> Paramètre à ajouter/enlever
     * @return <Date> Date du lendemain
     */
    public function alter($_param) {
	if ( preg_match('!^(\-|\+)([0-9]+) month$!i', $_param, $results) ) {
	    $moisCible = $this->format('m');
	    $anneeCible = $this->format('Y');
	    if ( $results[1] == '-' ) {
		$moisCible -= $results[2];
		if ( $moisCible < 1 ) {
		    // Complément pour être multiple de 12 ?
		    $anneeCible += $moisCible%12;
		    $moisCible = 12 + ($moisCible%12);
		}
	    }


	    elseif ( $results[1] == '+') {
		$moisCible += $results[2];
		if ( $moisCible > 12 ) {
		    $anneeCible += floor($moisCible/12);
		    $moisCible %= 12;
		}
	    }
	    $date = new Date($anneeCible.'/'.$moisCible.'/'.$this->format('d'));
	    return $date;

	}
	else {
	    $date = new Date($this->format('Y/m/d'));
	    $date->modify($_param);
	    return $date;
	}
    }

}


?>